Programming
***********

This chapter handles problems arising for programmers and compiler-users only.

What documentation do I need as an Amiga programmer?
====================================================

The best information available are the RKMs (ROM Kernel Manuals), 3rd edition, by Commodore, published by Addison-Wesley:

     The Amiga ROM Kernel Manual:  Libraries, ISBN 0-201-56774-1
     The Amiga ROM Kernel Manual:  Devices, ISBN 0-201-56775-X
     The Amiga ROM Kernel Manual:  Includes and Autodocs, ISBN
                                                          0-201-56773-3
     The Amiga Hardware Manual, ISBN 0-201-56776-8
     The Amiga User Interface Style Guide, ISBN 0-201-57757-7

Especially the RKM: Libraries is a must. The RKM: Includes and Autodocs isn't that much worth: Better get the same stuff on disk instead to have it online. See Includes.

AmigaDOS isn't included in these books. The Autodocs give much information, but to go deeper you probably need

     The AmigaDOS Manual, 3rd Edition, ISBN 0-553-35403-5

published by Bantam Books.

A better choice for developers is

     The Amiga Guru Book

by Ralph Babel. The book starts with a survey on different aspects of programming the Amiga. (About 250 pages) Useful for beginners are the sections on the Amiga's data types (not to be confused with the 3.x DataTypes used by MultiView, for example), the Includes and the amiga.lib. But even experienced programmers will find useful things here that are missing in the RKMs. But the largest part are about 500 pages on AmigaDOS and, as I think, the most important, because AmigaDOS is the worst officially documented part of the OS. The book is rather concise and hence not as easy to read as the RKMs, but I recommend it as an addition and instead of the AmigaDOS manual. (Not, however, a replacement for the Libraries and Devices, which aren't covered here.) Unfortunately the book has no ISBN and is available in special stores only. But there are some mail order companies which offer it for about 50$ and which accept credit cards:

                                 Almathera Systems Limited
                                 Southerton House
     NBG USA, Inc.               Boundary Business Court
     482 Holly Avenue            92-94 Church Road
     St. Paul, MN 55102          Mitcham, Surrey CR4 3TD
     USA                         England
     Voice: +1 (612) 290 9447    Voice: +44 181 687 0040
     Fax:   +1 (612) 290 9449    Fax:   +44 181 687 0490
                                 E-Mail: <almathera@cix.compulink.co.uk>

                                 Stefan Ossowskis Schatztruhe
     Hirsch & Wolf OHG           Gesellschaft für Software mbH
     Mittelstraße 33             Veronikastraße 33
     D-56564 Neuwied             D-45131 Essen
     Germany                     Germany
     Voice: +49 (2631) 8399-0    Voice: +49 (201) 788778
     Fax:   +49 (2631) 8399-31   Fax:   +49 (201) 798447
                                 E-Mail: <stefano@tchest.e.eunet.de>

     Someware
     27 rue Gabriel Péri
     59186 Anor
     France
     Voice: +33 27596000
     Fax:   +33 27595206
     E-Mail: <didierj@swad.someware.com>

See FAQs.

What is CATS?
=============

This is a department at Commodore West Chester which was formerly named Commodore Amiga Technical Support and was later renamed Commodore Application and Technical Support. These are people that work independently of Engineering, but close together with them, and try to help developers outside of Commodore to create nice Amiga applications, software or hardware. To achieve this, CATS has gathered a lot of informations and tools, on floppy, CD, or paper. Much of this material is also available to the general public.  (Which means: For Non-Developers.) But don't mix this up with some sort of Hotline for everyone!

For Americans the address to get this material is

         CATS
         Commodore Electronics Limited
         950 Rittenhouse Road
         Norristown, PA 19403

for all Europeans it's a company in Germany:

         Fa. Hirsch & Wolf
         Mittelstr. 33
         56564 Neuwied
         Tel. 02631/83990

Dr. Peter Kittel, peterk@cbmger.de.so.commodore.com

Where do I get the Amiga includes?
==================================

The only legal way to get the includes and autodocs (and you should get them, they are very useful!) is to become a developer (see Developer) or to buy the NDU (Native developers update kit, also known as NDUK or NDK), which is offered by CATS. They cost about 30$ plus shipping and this seems to me to be a fair price. See CATS. The current version is 3.1.

If you need only the includes, you could get them as well with a compiler (commercial compilers only) or by getting the Fresh Fish CD. See Fish CD.

How do I become a developer?
============================

You need the ADSP (Amiga Developer Support Program) documents. To get this write a letter to your local Commodore branch asking for these documents. Everything else should be explained there. The german address (for the US address see CATS) is

         Commodore
         Lyoner Strasse 38
         60528 Frankfurt

There are three different developer versions:

Registered
     developers get access to the CBMNET (kind of a Commodore-internal Usenet), which makes it possible to discuss problems with other developers, Commodore engineers included. Registered developers pay about US$80 per year, plus initial US$30 initially.

Certified
     developers seem to me the most interesting claass: They have the possibility copy the most beta versions of the system software (Kickstart and Workbench) and the respective Includes and AutoDocs. (Not all beta versions and especially no beta hardware.) You pay about US$250 per year plus US$50 initially for this.

Commercial
     developers finally have in most details the same as certified developers, but may expect to get more beta versions and sooner, included beta hardware (This has not always been so in the past.), hencethey pay about US$400 plus US$50 initially.

The above describes the prices and the situation in Germany and might be different elsewhere. Especially not all Commodore branches offer the registered status. A hint is to build a group of users and become a developer group, so the costs are reduced.

All developers have to sign non-disclosure agreements (NDA) which specify that we may not discuss information outside of authorized areas even to other developers until given explicit permission by Commodore.

What compilers (assemblers) are there?
======================================

There is a lot of programming languages on the Amiga, commercial as well as freely distributable. I will enumerate only those that I know or which seem it worth to me otherwise.

Assembler
     All C-compilers have an Assembler included. Freely distributable are A68K and PhxAss (directory dev/asm on Aminet or Fish disks 521 and 906)

C
C++
     Freely distributable C-compilers are gcc (which has its own directory dev/gcc on Aminet) and the evaluation version of Dice (for example per FTP from ftp.uni-paderborn.de, directory /news/comp.binaries.amiga/volume91/languages or on Fish disk 491). The advantage of gcc is that you find gcc versions all over the world and on all computer systems. Another advantage is that C++ is included into gcc! But it is slow and needs 4Mb of RAM or more. See The GNU C compiler. See Mailing lists.

     Commercial C compilers are Aztec-C, Dice and SAS/C. Aztec-C doesn't seem to get further development any more. It should be remarked that the commercial compilers have especially wonderful debugging utilities (Source level debuggers!) that the others are missing.

     SAS/C has announced to drop support of the Amiga-Compiler, too, due to the Amiga's bad situation. However, the compiler is still available and up-to-date and has a crosscompiler included, which translates C++ to C and supports the source level debugger too. Considering the price of just 99$ for students and updates from recent versions or other compilers it is still the most recommendable of the three. In europe the compiler is available from

              SAS Institute GmbH
              PO Box 10 53 40
              69043 Heidelberg
              Germany

              Phone: (49)6221-4160
              EMail: eurdoc2@vm.sas.com

     Dice is the cheapest and fastest commercial compiler. The greatest disadvantage of Dice (compared to the other commercial compilers) is the so-called Source-Line-Debugger: This means that you see the current line of source and can execute the program step by step, like with the other debuggers. On the other hand you can examine memory only, not the variables. To get information about DICE, send email to info@oic.COM. An automatic system will return complete details, including upgrade prices.

     Comeau C++ is a crosscompiler like SAS/C++. That wouldn't be a problem, but Comeau C++ doesn't have a C compiler included. You need SAS/C, Aztec-C or Dice additionally. But it is AT&T cfront 3.0 compliant and supports exceptions. And like gcc it runs on many platforms. Maxxon C++ is offered in Germany. I cannot say anything on it. Both compilers are commercial. Comeau's address is:

              Comeau computing
              91-34, 120th Street
              Richmond Hill, NY, 11418-3214
              USA

              EMail: Greg Comeau, comeau@bix.com

Forth
     JForth is said to be an excellent Amiga port of Forth. Among its advantages are object oriented extensions, full Amiga interface and an application generator. It is available from:

              Delta Research
              P.O. Box 151051
              San Rafael, CA   94915-1051

              Phone: (415) 453-4320
              EMail: Phil Burk, phil@ntg.com
                     Mike Haas, haas@starnine.com

Fortran
     (Sigh! Still people who need it :-<) Freely distributable are BCF (Fish disk 470) and f2c, a Fortran to C converter (Aminet, directory /dev/lang). A commercial compiler is offered from ABSoft. All these are Fortran 77 compilers, I don't know any Fortran 90 compiler on the Amiga.

Lisp
     Freely distributable Lisp interpreters are XLisp (Fish disk 181) and OakLisp (Fish disks 519 and 520) and CLISP (/pub/lisp/clisp/binaries/amiga at the server ftp ma2s2.mathematik.uni-karlsruhe.de). Lisp compilers are Gambit (Fish 764 and 765) and Scheme-to-C (Fish disks 556, 557 and 558). See Mailing lists.

Prolog
     /dev/lang/UNSWProlog.lha and dev/lang/sbp3_1e.lha on Aminet as well as SBProlog on Fish disk 141 and SBProlog on Fish disk 145 are freely distributable Prolog interpreters.

Modula-2
     M2Amiga is offered in Europe, Benchmark Modula-2 in the U.S. Both are said to be very good, have a powerful source-level-debugger, a large library. Especially M2Amiga has great support by a german user-group (AMOK) which for example offers own PD disks. See Mailing lists.

     M2Amiga is offered by:

              A+L AG
              Daderiz 61
              2540 Grenchen
              Schweiz

              Tel.: +41/65/52 03-11
              Fax:              -79

     Benchmark Modula-2 is available from:

              Armadillo Computing
              5225 Marymount Drive
              Austin, Texas 78723
              USA

              Phone/FAX: 512/926-0360.
              EMail: Jim Olinger, jolinger@bix.com

Oberon
Oberon-2
     Two compilers (both Oberon-2) are available: AmigaOberon (commercial) is offered by the same company as M2Amiga. It is integrated into a full developers environment and has a large library of modules. Library linker and  source level debugger are available.

     Oberon-A is a Freeware compiler. (Source: Aminet, dev/obero directory) However, this is a beta release, especially the module library is limited. See Mailing lists.

     The AMOK user group supports AmiOberon as well as M2Amiga.

Pascal
     There is a PD-compiler called PCQ (Directory dev/lang on Aminet or Fish disk 511). It doesn't support all of Pascal and major features are missing. P2C, a pascal to C converter is on disk 341. (Aminet: /dev/misc/p2c120.lha) Additionally there are two commercial compilers called HiSoft Pascal and KickPascal. HiSoft Pascal and P2C claim to be compatible to Turbo Pascal up to 5.0. HiSoft has a source level debugger included.

Those never working Esc sequences!
==================================

Many printers come with a manual that explains which Esc sequence causes which action on the printer. But there happen weird things when you try to send these sequences to your printer, either it does nothing, or it does something completely different. There is a reason, the Amiga printer drivers. These drivers are made in a way that they only understand a certain set of ANSI Esc sequences, not the special ones defined (differently) by the various printer manufacturers. The purpose is that every application on the Amiga just uses this one standard set of control sequences and this way doesn't need to know which printer is actually connected. The printer driver then translates these standard sequences into the special sequences a certain printer understands. A list of the available ANSI Esc sequences is found in the current Workbench manuals (or older AmigaDOS manuals). Now if you want to issue a control sequence to the printer that's not available as an ANSI command, you have two possibilities to achieve this:

 1. Bypass the printer driver (that would unsuccessfully try to interpret the sequence) and send your output only during this sequence to PAR: (or SER:, respectively). For this you have to close and open printer output channels very often which is rather tedious, and you have to know where (PAR: or SER:) your printer is connected.

 2. Use a special ANSI sequence, made exactly for this case:

              Esc[<n>"<x>

     where <n> is the decimally typed number of bytes in the string <x>, which actually contains your special printer sequence. This ANSI sequence tells the printer driver to not interpret or translate the next <n> bytes.

But both methods have one big disadvantage when used in an application program: You lose the printer independency! If you stick to ANSI sequen- ces, you can output to any printer on earth, as long as there is an Amiga printer driver for it. If you start to use special control sequences, your program will be tied to this single printer model and will not be usefull for any other (or you would have to provide some dozen new printer drivers for your application).

Dr. Peter Kittel, peterk@cbmger.de.so.commodore.com

Is it possible to use AmigaBasic on the A1200?
==============================================

We heard conflicting reports about AmigaBasic on the A1200: While I said that you can work sufficiently with it, others said that this isn't possible, as AmigaBasic crashes on the slightest little error. I couldn't reproduce this.

Now I can. It depends on the setting in the Sound Prefs editor. When you activate a sound there, this conflicts with sound that AmigaBasic tries to produce by hand and obviously not quite the correct way itself.

Easy solution: To work with AmigaBasic on the A1200, just

 1. Switch off sound output in the Sound prefs editor.

 2. On the A4000 (as well as on an A1200 with Fast Mem expansion (If you have a turbo board)) you  additionally need to run NoFastMem.

 3. Better avoid SUBs and use conventional GOSUBs instead, then the compatibility with newer processors will be higher.

Dr. Peter Kittel, peterk@cbmger.de.so.commodore.co

How do I localize my program?
=============================

Suggest, you want to write a HelloLocalWorld.c. Your final program will look like this:

         #include "HelloLocalWorld_Cat.h"
         #include <clib/exec_protos.h>

         struct Library *LocaleBase;

         void main(int argc, char *argv[])

         {
             /* Open the locale.library. No kill, if not successfull.
                (Just use the builtin catalog strings instead.) Note, that
                we open locale.library here, even if our compiler supports
                AutoOpening.
             */
             LocaleBase = OpenLibrary("locale.library", 38);
             OpenHelloLocalWorldCatalogs(NULL, NULL);

             printf(GetString(MSG_Hello));

             CloseHelloLocalWorldCatalog();
             if (LocaleBase) CloseLibrary(LocaleBase);
         }

The routine GetString checks, if the wished catalogs are available and returns a pointer to either the builtin string or the catalog string. (In my case the german string.)

You see, the main difference besides the minor opening and closing stuff (OpenLibrary, OpenHelloLocalWorldCatalogs, ...) is to replace strings with a function call. Hence we need a file HelloLocalWorld_Cat.c, which holds OpenHelloLocalWorld, GetString, CloseHelloLocalWorld and the builtin strings (this could be an array, where

             array[MSG_Hello] = "Hello, local world.\n";

is defined) and an include file HelloLocalWorld_Cat.h, which defines the message ID's like MSG_Hello. You don't need to know, how these files work internally, especially you don't need to know locale.library!

There are some catalog generators (in what follows: CGs) available (CatComp, for devlopers only, KitCat, german docs only, MakeCat, which I don't know and FlexCat, which I  recommend, because it is most flexible in the generated source and supports catalogs on 2.0 and any language, even Amiga-E, Cluster, Pascal, ... and besides that: I'm the author ;-) are tools, that create  HelloLocalWorld_Cat.h, HelloLocalWorld_Cat.c and the real catalogs for you. (The above code might differ slightly between the different CGs.) (See Aminet, directory dev/misc.)

Of course they need to know how to use them. First create a so-called catalog-description file. This could look like this:

         ; Lines beginning with a semicolon are comment lines.
         # language english
         ; the language of the builtin strings
         # version 0
         ; the catalog version (0 = any)
         MSG_Hello (1/15/30)
         Hello, local world

Any string is defined by a line like the last two lines above: MSG_Hello is the message-ID, (1/15/30) says, that the value of MSG_Hello should be 1 (you may omit this, in which case just the next free number is used) and the string must not be shorter than 15 characters or longer than 30 characters. (These may be omitted too.)

Now write your program. Once you are ready, use the CGs to create a so-called catalog translation file. (One for any language different than the builtin.) In my case (german) this could look like this:

         ; Lines beginning with a semicolon are comment lines.
         ## language deutsch
         ; the catalog language (german)
         ## version $VER: Deutsch.catalog 1.0 (22.12.93)
         ; the catalog files version string
         MSG_Hello

         ; Hello, local world

Note the empty line after the message ID. (The arguments of ## language and ## version would be missing as well.) You have to fill in the german strings here. Again using the CGs you create a catalog file from this. Additionally note, that no informations on the strings ID or length are behind MSG_Hello. They are taken from the catalog description file.

Once you change the program (adding strings, changing the string length) you change the catalog description as well, use the CGs in the same way to update the catalog translation and hence the catalogs.

How to obtain a pointer to a console's window
=============================================

The following function returns the window pointer of a CON window. It can be executed safely under all versions of the Amiga's OS.

       struct Window *getConWindowPtr(BPTR fh)
       {
         struct Window *w;
         struct FileHandle *cfh;
         struct StandardPacket *sp;
         struct InfoData *id;
         struct MsgPort *mp;

         w = NULL;

         if ((cfh = BADDR(fh))->fh_Type != NULL) {
           if (sp = AllocMem(sizeof (struct StandardPacket),
                             MEMF_PUBLIC | MEMF_CLEAR)) {
             if (id = AllocMem(sizeof (struct InfoData),
                               MEMF_PUBLIC | MEMF_CLEAR)) {
               if (mp = CreatePort(NULL, 0)) {
                 sp->sp_Msg.mn_Node.ln_Name = (char *) &sp->sp_Pkt;
                 sp->sp_Pkt.dp_Link         = &sp->sp_Msg;
                 sp->sp_Pkt.dp_Port         = mp;
                 sp->sp_Pkt.dp_Type         = ACTION_DISK_INFO;
                 sp->sp_Pkt.dp_Arg1         = MKBADDR(id);

                 PutMsg(cfh->fh_Type, &sp->sp_Msg);
                 (void) WaitPort(mp);
                 (void) GetMsg(mp);

                 if (sp->sp_Pkt.dp_Res1)
                   w = (struct Window *) id->id_VolumeNode;

                 DeletePort(mp);
               }
               FreeMem(id, sizeof (struct InfoData));
             }
             FreeMem(sp, sizeof (struct StandardPacket));
           }
         }

         return w;
       }

Notes:

  * Accessing a console's window directly may interfere with operations performed by the CON handler. Be careful!

  * To obtain the window pointer of a CLI's console, pass the FileHandle returned by Open("*", MODE_OLDFILE) to the above function.

  * The result of the above function may well be NULL, e.g. in case of an AUX handler or if an AUTO CON handler is unable to open its window.

  * Sending an ACTION_DISK_INFO packet to an AUTO CON handler (2.0+) causes its window to lose its special AUTO properties (i.e. it can no longer be closed at any time by clicking on its Close gadget), as the window pointer returned in id_VolumeNode must remain valid from now on.

  * All in all: Don't use this function. :-)

For more information, please refer to pages 273, 276, 435, 463, 485, and 629 in "The Amiga Guru Book" (see Manuals).

Ralph Babel, rbabel@babylon.pfm-mainz.de

What are pragmas?
=================

Pragmas are special compiler commmands which control certain features of a C-compiler. Two problems arise when using pragmas:

 1. Pragmas are compiler specific. You cannot expect that one compiler will understand pragmas of another compiler, even if both run on the Amiga.

 2. You are not guaranteed that a compiler ignores pragmas, that he doesn't understand. Even more: It might not help, to use something like this:

              #ifndef MY_COMPILER
              #pragma DoAnything
              #endif

A workaround is to put pragmas in a special include file (BTW, the same holds true for statements like #asm (Aztec-C) or #extern (C++) and replace the above with

         #ifndef MY_COMPUTER
         #include <mypragmas.h>
         #endif

But what do pragmas on the Amiga? The most common usage (not the only, but most meant when talking about pragmas) is to tell the compiler about how to call library functions: Simple C functions expect their arguments on the stack, but library functions want their arguments in special processor registers and additionally the library base in register a6. Lets have a look at a pragma command of the Aztec-Compiler.

         #pragma amicall(SysBase,0xd2,FreeMem(a1,d0))

This tells the compiler to put the first argument of FreeMem in register a1, the second in register d0 and the value of the variable SysBase in register a6. Maxons pragmas look the same, Dice pragmas and SAS pragmas look a bit more complicated;

         #pragma libcall SysBase FreeMem d2 0902

Here d2 is (like 0xd2 above) the library vector offset (see below), the digits 09 are codes for the argument register in reversed order (Register codes are 0=d0, 1=d1, .., 8=a0, 9=a1, a=a2, ..), the following 0 is the result's registerä(always d0))and the final digit 2 is the number of arguments.

A command FreeMem(fib,sizeof(*fib); could produce the following code, if the compiler has seen a pragma statement like above:

         move.l  _fib,a1
         move.l  260,d1	    ; sizeof(struct FileInfoBlock)
         move.l  _SysBase,a6
         jsr     -0xd2(a6)       ; 0xd2 = _LVOFreeMem

Calling FreeMem in that way is shorter and faster than pushing the arguments on the stack, calling a function _FreeMem which would do just the same like the above code by pulling the arguments from the stack.

The best way to use pragmas is to include statements like the following in your program:

         /*	Get the prototype for the function; note, that this is	*/
         /*	compiler independent.					*/
         #include <clib/exec_protos.h>

         /*	Get the pragma; compiler dependent, but most pragmas	*/
         /*	are in files with the same name.
         #ifdef AZTEC_C
         #include <pragmas/exec_lib.h>
         #endif
         #if defined(__SASC) || defined(_DCC) || defined(__MAXON__)
         #include <pragmas/exec_pragmas.h>
         #endif
         #ifdef __GNUC__
         #include <inline/exec.h>
         #endif

The above example can be compiled on all these compilers and produce the best code.

A final question arises: How to get the pragmas? Most compilers have them included. However, sometimes you want to produce pragmas for yourself, for example if you are using new libraries or new versions with additional functions. In that case you can produce them from the so-called FD files which should be a part of the developer docs of the library. (The NDU has a directory FD which contains FD files for all libraries and devices of the OS. see Includes) Most compilers have a utility with the name fd2pragma or similar included which can do that for you. A freely distributable version which can produce pragmas for Aztec, Dice, SAS and Maxon as well as LVO files for assembler and stub routines for the tag versions is available on Aminet (dev/misc/fd2pragma2_0.lha and on the Fish CDs.

For pragmas under gcc see Inline Headers.

My Compiler/Linker is complaining about missing symbol xxx.
===========================================================

First be sure, that the function is really missing: For example floating point functions are in a special link library and you need a linker option like -lm to include it into your program. Another possibility would be that you are using a library function and didn't notice it. This might lead to a missing library base, IntuitionBase for example. In that case just put something like

         struct Library *IntuitionBase;

somewhere in the global part of your program. (Don't forget to call OpenLibrary() and CloseLibrary! :-)

However, you could as well use a function which really isn't present in your library at all. If you have, for example, an amiga.lib from 2.0 you would hardly find the locale functions or the pool memory functions.  (This problem arises most frequently for owners of Aztec which is no longer supported and owners of Dice, which has sometimes rather incomplete libraries. I own both ...) Best solution is to get the NDU (see Includes), but you probably don't want to wait for it. In that case you have to find what kind of function you are missing.

  * Simple library functions (Examples: exec/AllocPooled, locale/OpenCatalogA) can be called with pragmas. However, you need informations on the name of the library base and where to put the arguments. See Pragmas.

  * Tag functions are mostly just stub functions which call library functions. If you have, for example, dos/AllocDosObject which expects a constant and a pointer to an array of tags, you have the varargs version AllocDosObjectTags which expects tags on the stack as well! Just create the following function:

              #include <clib/dos_protos.h>
              #include <pragmas/dos_pragmas.h>	/*  Probably wrong name */

              void *AllocDosObjectTags(ULONG objtype, Tag tag1, ...)
              { return(AllocDosObject(objtype, (struct TagItem *) &tag1);
              }

  * Some functions still remain: Amiga.lib has some functions which are really doing valuable things and not just call a library: The BOOPSI functions (DoMethod, DoSuperMethod) the memory pool functions (LibAllocPooled, LibCreatePool, which are replacements of 3.0 functions). The only way to replace these is to get equivalents. The AmigaFAQ archive contains some of them (DoMethod, DoSuperMethod and HookEntry) in the programmer directory as well as the most common pragma files and some examples of varargs functions. See Amiga-FAQ Archive.

Where do I find the function xxx?
=================================

If you are not sure about the name of the appropriate function for a certain job or in which library to find it, you can search in these places:

  * In the Autodocs for each library you find at the very beginning a contents table listing all functions available in this library. They are sorted alphabetically, just like in the rest of the Autodocs. In the body part of the Autodocs you find complete explanations and specifications for each library function. See Includes.

  * The .FD files also offer a very compact overview over all functions of the diverse libraries, complete with a short information about the function arguments. If you already know roughly what you search for and e.g. only need the precise order of the arguments, you can find all needed information here. See Pragmas.

Dr. Peter Kittel, peterk@cbmger.de.so.commodore.com

     [file prog-gcc-e.texinfo not included]